//----------------------------------------------------------
    // 日志器模块：将各个模块整合起来实现日志的输出
        // 同步日志器————日志生成即进行日志落地
        // 异步日志器————日志生成与日志落地交由不同的线程来进行
//----------------------------------------------------------

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif //_GNU_SOURCE

#ifndef __LOGGER__
#define __LOGGER__

#include "asyncthread.hpp"
#include "logfmt.hpp"
#include "loglevel.hpp"
#include "logmes.hpp"
#include "logsink.hpp"
#include <atomic>
#include <memory>
#include <mutex>
#include <stdarg.h>
#include <string>
#include <unordered_map>
#include <vector>


namespace ymbxlog
{
    #define THREAD_CNT 2
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, LogLevel::Level lev, Formatter::ptr fmt, std::vector<LogSink::ptr> &sinks) : _logger_name(logger_name), _limit_lev(lev), _fmtp(fmt), _sinks(sinks) {}
#if __cplusplus >= 201103L
        template<typename ...Args>
        void Debug(size_t line,const std::string& file,const std::string& func,Args&& ...args){
            if (LogLevel::Level::DEBUG < _limit_lev)
            {
                return;
            }
            LoadLog(line,file,func,LogLevel::Level::DEBUG,std::forward<Args>(args)...);
        }
        template<typename ...Args>
        void Info(size_t line,const std::string& file,const std::string& func,Args&& ...args){
            if (LogLevel::Level::INFO < _limit_lev)
            {
                return;
            }
            LoadLog(line,file,func,LogLevel::Level::INFO,std::forward<Args>(args)...);
        }
        template<typename ...Args>
        void Warn(size_t line,const std::string& file,const std::string& func,Args&& ...args){
            if (LogLevel::Level::WARNING < _limit_lev)
            {
                return;
            }
            LoadLog(line,file,func,LogLevel::Level::WARNING,std::forward<Args>(args)...);
        }
        template<typename ...Args>
        void Error(size_t line,const std::string& file,const std::string& func,Args&& ...args){
            if (LogLevel::Level::ERROR < _limit_lev)
            {
                return;
            }
            LoadLog(line,file,func,LogLevel::Level::ERROR,std::forward<Args>(args)...);
        }
        template<typename ...Args>
        void Fatal(size_t line,const std::string& file,const std::string& func,Args&& ...args){
            if (LogLevel::Level::FATAL < _limit_lev)
            {
                return;
            }
            LoadLog(line,file,func,LogLevel::Level::FATAL,std::forward<Args>(args)...);
        }
#else
        void Debug(size_t line, const std::string &file, const std::string& func,const char *fmt, ...)
        {
            if (LogLevel::Level::DEBUG < _limit_lev)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            LoadLog(line, file, func, fmt, ap, LogLevel::Level::DEBUG);
            va_end(ap);
        }
        void Info(size_t line, const std::string &file,  const std::string& func,const char *fmt, ...)
        {
            if (LogLevel::Level::INFO < _limit_lev)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            LoadLog(line, file, func, fmt, ap, LogLevel::Level::INFO);
            va_end(ap);
        }
        void Warn(size_t line, const std::string &file,  const std::string& func,const char *fmt, ...)
        {
            if (LogLevel::Level::WARNING < _limit_lev)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            LoadLog(line, file, func, fmt, ap, LogLevel::Level::WARNING);
            va_end(ap);
        }
        void Error(size_t line, const std::string &file,  const std::string& func,const char *fmt, ...)
        {
            if (LogLevel::Level::ERROR < _limit_lev)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            LoadLog(line, file, func, fmt, ap, LogLevel::Level::ERROR);
            va_end(ap);
        }

        void Fatal(size_t line, const std::string &file,  const std::string& func,const char *fmt, ...)
        {
            if (LogLevel::Level::FATAL < _limit_lev)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            LoadLog(line, file, func, fmt, ap, LogLevel::Level::FATAL);
            va_end(ap);
        }
#endif
        std::string GetLoggerName()
        {
            return _logger_name;
        }
        void AddSink(LogSink::ptr ptr)
        {
            _sinks.push_back(ptr);
        }
        virtual void Log(const std::string &mes) = 0;

    protected:
#if __cplusplus >=201103L
        // 基于递归的可变参数模板函数实现
        std::string GetMes(){
            return "";
        }
        template<typename T,typename ...Args>
        std::string GetMes(T&& m,Args&& ...args){
            std::stringstream ss;
            ss<< std::forward<T>(m);
            return ss.str()+GetMes(std::forward<Args>(args)...);
        }
        // 基于逗号表达式的可变参数模板函数实现
        template<typename T>
        void GetMess(std::ostringstream& oss,T&& m){
            oss<<std::forward<T>(m);
        }
        template<typename ...Args>
        void LoadLog(size_t line,const std::string& file,const std::string& func,LogLevel::Level lev,Args&& ...args){
            std::string mes=GetMes(std::forward<Args>(args)...);
            // std::ostringstream oss;
            // int arr[]={(GetMess(oss,std::forward<Args>(args)),0)...};
            // std::string mes=oss.str();
            LogMes lm(line,_logger_name,file,func,mes,lev);
            Log(_fmtp->Format(lm));
        }
#else
        void LoadLog(size_t line, const std::string &file, const std::string& func,const char *fmt, va_list ap, LogLevel::Level lev)
        {
            char *buffer;
            int ret = vasprintf(&buffer, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf 错误" << std::endl;
                return;
            }
            LogMes lm(line, _logger_name, file, func, buffer, lev);
            Log(_fmtp->Format(lm));
            free(buffer);
        }
#endif
        
    protected:
        std::string _logger_name;
        // 多线程环境中可能会产生数据竞争而不一致的情况，所以采用轻量级的atomic
        std::atomic<LogLevel::Level> _limit_lev;
        std::mutex _mtx;
        Formatter::ptr _fmtp;
        std::vector<LogSink::ptr> _sinks;
    };
    // 同步日志器
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::Level lev, Formatter::ptr fmt, std::vector<LogSink::ptr> &sinks) : Logger(logger_name, lev, fmt, sinks)
        {}
        virtual void Log(const std::string &mes) override
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->Log(mes);
            }
        }
    };
    // 异步日志器
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, LogLevel::Level lev, Formatter::ptr fmt, std::vector<LogSink::ptr> &sinks, size_t thread_cnt=THREAD_CNT) : Logger(logger_name, lev, fmt, sinks), _asynctp(std::make_shared<AsyncLooper>(thread_cnt,std::bind(&AsyncLogger::RealLog, this, std::placeholders::_1))) {}
        // 将日志消息放在异步缓冲区中
        virtual void Log(const std::string &mes) override
        {
            _asynctp->Push(mes);
        }
        // 实际的日志落地
        void RealLog(Buffer& buf)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->Log(buf.RetStr());
            }
        }

    private:
        AsyncLooper::ptr _asynctp;
    };
    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 采用建造者模式建造Logger
    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _type(LoggerType::LOGGER_SYNC), _limit_lev(LogLevel::Level::DEBUG){}
        // 日志类型默认为同步日志写入
        void EnableLoggerSync() { _type = LoggerType::LOGGER_SYNC; }
        void EnableLoggerAsync() { _type = LoggerType::LOGGER_ASYNC; }

        void BuildLoggername(const std::string &name) { _logger_name = name; }
        void BuildLimitLevel(LogLevel::Level lev) { _limit_lev = lev; }
        void BuildFormatter(){ _fmtp=std::make_shared<Formatter>(); }
        void BuildFormatter(const std::string &pattern)
        {
            if (pattern.empty())
            {
                _fmtp = std::make_shared<Formatter>();
                return;
            }
            _fmtp = std::make_shared<Formatter>(pattern);
        }
        void BuildAsyncThreadCnt(size_t thread_cnt){
            if(_type==LoggerType::LOGGER_SYNC){
                return;
            }
            _async_thread_cnt=thread_cnt;
            return;
        }
        template <typename SinkType, typename... Args>
        void BuildSink(Args &&...args)
        {
            _sinks.push_back(std::make_shared<SinkType>(std::forward<Args>(args)...));
        }
        virtual Logger::ptr Build() = 0;

    protected:
        LoggerType _type;
        std::string _logger_name;
        LogLevel::Level _limit_lev;
        Formatter::ptr _fmtp;
        std::vector<LogSink::ptr> _sinks;
        size_t _async_thread_cnt=-1;
    };
    // 建造者可以分为局部建造者和全局建造者
    // 局部建造者
    class LocalLoggerBuild : public LoggerBuilder
    {
    public:
        virtual Logger::ptr Build()
        {
            if(_logger_name.empty()){
                std::cout<<"请设置日志器名后重新尝试"<<std::endl;
                abort();
            }
            if (_fmtp.get() == nullptr)
            {
                _fmtp = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }
            if (_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_lev, _fmtp, _sinks);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_lev, _fmtp, _sinks);
        }
    };

    // 日志器管理器————单例模式，只有一个日志管理器，管理多个日志器
    class LoggerManager
    {
    public:
        void AddLogger(const Logger::ptr &log)
        {
            if (IsExist(log->GetLoggerName()))
                return;
            std::unique_lock<std::mutex> lock(_mtx);
            _loggers.insert(std::make_pair(log->GetLoggerName(), log));
        }
        bool IsExist(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }
        Logger::ptr GetLoggerByName(const std::string& name){
            if(IsExist(name))
                return _loggers[name];
            return Logger::ptr();
        }
        static LoggerManager &GetInstance()
        {
            static LoggerManager _logmag;
            return _logmag;
        }
        const Logger::ptr &GetRootLoggerByName()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> upl(new LocalLoggerBuild());
            upl->BuildLoggername("root");
            _root_logger = upl->Build();
            _loggers.insert(std::make_pair(_root_logger->GetLoggerName(), _root_logger));
        }
        LoggerManager(const LoggerManager &log) = delete;

    private:
        std::mutex _mtx;
        Logger::ptr _root_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };
    // 全局建造者————打破作用域的限制
    class GlobalLoggerBuild : public LoggerBuilder
    {
    public:
        virtual Logger::ptr Build()
        {
            if(_logger_name.empty()){
                std::cout<<"请设置日志器名后重新尝试"<<std::endl;
                abort();
            }
            if (_fmtp.get() == nullptr)
            {
                _fmtp = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }
            Logger::ptr logger;
            if (_type == LoggerType::LOGGER_ASYNC)
            {
                if(_async_thread_cnt==-1){
                    logger = std::make_shared<AsyncLogger>(_logger_name, _limit_lev, _fmtp, _sinks);
                }else{
                    logger = std::make_shared<AsyncLogger>(_logger_name, _limit_lev, _fmtp, _sinks,_async_thread_cnt);
                }
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_lev, _fmtp, _sinks);
            }
            LoggerManager::GetInstance().AddLogger(logger);
            return logger;
        }
    };
}
#endif //__LOGGER__

